/*
 * Copyright 2012 Alain Pannetrat (L1L1@gmx.com)
 * 
 * This file is part of cookie-miner.
 * 
 * cookie-miner is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * cookie-miner is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License 
 * along with cookie-miner. If not, see http://www.gnu.org/licenses/.
 *
 * @version: $Id$
 *
 */
#ifndef _JSON_H_
#define _JSON_H_

#include <string>
#include <vector>
#include "dictionary.h"
#include "bufio.h"
#include <cstdio>
#include "common.h"


namespace Json {
	class Value;

	extern Value Undefined;
	extern std::string _dummy;

	Value* create_object();
	Value* create_array();
	Value* create_string(const char *str);
	Value* create_string(const std::string& str);
	Value* create_number(double num);
	Value* create_number(int num);
	Value* create_boolean(bool b);
	Value* create_null();
	Value* unserialize(BufferIn *in);
	Value* unserialize(const std::string &source);

	class Value {
		public:
			friend Value* create_object();
			friend Value* create_array();
			friend Value* create_string(const char *str);
			friend Value* create_string(const std::string& str);
			friend Value* create_number(double num);
			friend Value* create_number(int num);
			friend Value* create_boolean(bool b);
			friend Value* create_null();
			friend void unreference(Value* val);

			Value* reference() { ++_ref_count; return this; }


			virtual Value* clone() const { return Undefined.reference(); }

			virtual bool serialize(BufferOut *out, const std::string &prefix="") const;

			std::string& serialize(std::string &result=_dummy, const std::string &prefix="") const; 
			
			virtual Value* set(const std::string& index, Value *val) { 
				delete val; return this; }

			Value* set(const std::string& index, const char *val) {
				return set(index,create_string(val)); }

			Value* set(const std::string& index, const std::string& val) {
				return set(index,create_string(val)); }

			Value* set(const std::string& index, int num) {
				return set(index,create_number(num)); }

			Value* set(const std::string& index, double num) {
				return set(index,create_number(num)); }

			Value* set(const std::string& index, bool b) {
				return set(index,create_boolean(b)); }

			Value* set_null(const std::string& index) {
				return set(index,create_null()); }

			virtual Value* set(unsigned index, Value *val) { 
				delete val; return this; }

			Value* set(unsigned index, const char *val) {
				return set(index,create_string(val)); }

			Value* set(unsigned index, const std::string& val) {
				return set(index,create_string(val)); }

			Value* set(unsigned index, int num) {
				return set(index,create_number(num)); }

			Value* set(unsigned index, double num) {
				return set(index,create_number(num)); }

			Value* set(unsigned index, bool b) {
				return set(index,create_boolean(b)); }

			Value* set_null(unsigned index) {
				return set(index,create_null()); }


			virtual Value* get(const std::string& index) const { 
				return &Undefined; }

			virtual Value* get(unsigned index) const { 
				return &Undefined; }

			Value* array(const std::string& index) {
				Value* retval = get(index);
				if (!retval->is_defined()) 
				{
					retval = create_array();
					set(index,retval);
					return retval;
				}
				return retval; }

			Value* array(unsigned index) {
				Value* retval = get(index);
				if (!retval->is_defined()) 
				{
					retval = create_array();
					set(index,retval);
					return retval;
				}
				return retval; }

			Value* object(const std::string& index) {
				Value* retval = get(index);
				if (!retval->is_defined()) 
				{
					retval = create_object();
					set(index,retval);
					return retval;
				}
				return retval; }

			Value* object(unsigned index) {
				Value* retval = get(index);
				if (!retval->is_defined()) 
				{
					retval = create_object();
					set(index,retval);
					return retval;
				}
				return retval; }

			virtual Value* push_back(Value *val) { 
				delete val; return this; }

			Value* push_back(const char* str) 		{ return push_back(create_string(str)); }
			Value* push_back(const std::string& str) 	{ return push_back(create_string(str)); }
			Value* push_back(double num) 			{ return push_back(create_number(num)); }
			Value* push_back(int num) 			{ return push_back(create_number(num)); }
			Value* push_back(bool b) 			{ return push_back(create_boolean(b)); }
			Value* push_back_null() 			{ return push_back(create_null()); }

			virtual bool is_object() const 		{ return false; }
			virtual bool is_array() const 		{ return false; }
			virtual bool is_string() const 		{ return false; }
			virtual bool is_number() const 		{ return false; }
			virtual bool is_boolean() const 	{ return false; }
			virtual bool is_null() const 		{ return false; }
			bool is_defined() const 		{ return this!=&Undefined; }

			virtual bool equals(const Value* val) const 	{ return val==this; }
			virtual bool equals(const char *str) const	{ return false; }
			virtual bool equals(const std::string&) const 	{ return false; }
			virtual bool equals(int num) const		{ return false; }
			virtual bool equals(double num) const 		{ return false; }
			virtual bool equals(bool b) const		{ return false; }

			virtual std::string as_string() const 	{ return _type; }
			const char *as_cstring() const 		{ return as_string().c_str(); }
			virtual double as_double() const	{ return 0; }
			virtual int as_int() const		{ return 0; }
			virtual bool as_bool() const		{ return false; }

			virtual unsigned size() const 		{ return 0; }

			virtual void clear() 			{} 

			const char *type() 			{ return _type; }

			virtual ~Value() { }

			Value(const char *type="(undefined)") : _type(type), _ref_count(0) {}

		protected:		
			static void* operator new(size_t);
		       	static void operator delete(void *);
		private: 
			const char *_type;
			unsigned _ref_count;

			DISALLOW_COPY_AND_ASSIGN(Value);
	};

	inline void unreference(Value* val)
	{
		if (val->_ref_count)
			val->_ref_count--;
		else
			delete val;
	}	
}

#endif
